using System;
using System.Collections.Generic;
using TTXNA.src.Engine.Graphics;
using TTXNA.src.Engine.Companies;
using Microsoft.Xna.Framework;
using TTXNA.src.Util;
using TTXNA.src.Engine.Stations;
using TTXNA.src.Engine.World;

namespace TTXNA.src.Engine.Vehicles
{
    public class Vehicle : GameObject
    {
        public const float roadSpeedScale = 0.02f;

        protected bool isInService = true;

        protected VehicleInfo vehicleInfo;

        protected Dictionary<CargoType, List<CargoPacket>> currentLoad;
        
        protected float xSpeed, zSpeed; // MAKE A VECTOR2
        
        private DateTime dateBuilt;

        private List<Order> orderList;
        protected int currentOrder;

        protected DDDCoordinate currentDestinationCoord;
        protected DDDCoordinate finalDestinationCoord;
        
        protected Vector3 currentDestination;
        protected Vector3 finalDestination;

        private bool isStopped;
        protected bool needNewInterimDestination;
        
        public Vehicle(string name, VehicleInfo info, Company company, DateTime builtDate, Vector3 location) 
            : base(location)
        {
            isStopped = true;

            objectInfo = new ObjectInfo(company, ObjectType.Vehicle, name);

            vehicleInfo = info;
            currentDestination = new Vector3(-1, -1, -1);
            xSpeed = 0; 
            zSpeed = 0;
            dateBuilt = builtDate;
            currentLoad = new Dictionary<CargoType, List<CargoPacket>>();

            foreach (CargoType type in vehicleInfo.CargoList)
            {
                currentLoad[type] = new List<CargoPacket>();
            }

            orderList = new List<Order>();
            currentOrder = -1;


            //objectInfo = new ObjectInfo(company, ObjectType.Vehicle, name);
            //Mesh = Game.meshManager.CreateMesh(info.MeshPath, Location, new Vector3(0, 0, 0), ObjectType.Vehicle);
            //Mesh.Mesh.ScaleBy(new Vector3(1, 0.9f, 1));
        }

        public override string ToString()
        {
            //return objectInfo.Name + " is a " + objectInfo.ObjectType.ToString() + " owned by " + objectInfo.CompanyOwner.GetCompanyName();
            return string.Empty;
        }

        //public InstancedMesh IMesh
        //{
        //    get { return objectMesh; }
        //}

        public DDDCoordinate GetFinalDestination()
        {
            if (orderList.Count > 0 && currentOrder > -1)
            {
                return orderList[currentOrder].GetOrderCoord();
            }
            else
            {
                return new DDDCoordinate(-1, -1, -1);
            }
        }

        protected void ArrivedAtFinalDestination()
        {
            //if (!(orderList[currentOrder].DestinationStation is Depot))
            //{
            //    UnloadCargo();
            //    PickupCargo();
            //}

            //currentOrder = orderList.NextOrderNumber(currentOrder);
        }

        protected virtual void PickupCargo()
        {
            Station station = orderList[currentOrder].DestinationStation;
            List<List<CargoPacket>> delivery = new List<List<CargoPacket>>();

            foreach (CargoType type in currentLoad.Keys)
            {
                List<CargoPacket> received = station.SendOutCargo(type, vehicleInfo.GetCapacityOf(type) - CarryingAmount(type));
                if(received.Count > 0) delivery.Add(received);
            }

            foreach (List<CargoPacket> packetList in delivery)
            {
                foreach (CargoPacket packet in packetList)
                {
                    currentLoad[packet.CargoType].Add(packet);
                }
            }
        }

        private int CarryingAmount(CargoType type)
        {
            int amount = 0;

            foreach (CargoPacket packet in currentLoad[type])
            {
                amount += (int)packet.CargoAmount;
            }

            return amount;
        }

        protected virtual void UnloadCargo()
        {
            Station station = orderList[currentOrder].DestinationStation;
            List<CargoType> typesDelivered = new List<CargoType>();

            foreach (CargoType type in currentLoad.Keys)
            {
                if (station.Accepts.Contains(type))
                {
                    decimal moneyEarnt = station.ReceiveCargoFromVehicle(currentLoad[type]);
                    objectInfo.CompanyOwner.AddFunds(moneyEarnt);

                    typesDelivered.Add(type);
                }
            }

            foreach (CargoType type in typesDelivered)
            {
                currentLoad[type].Clear();
            }

        }

        

        public void SetLocation(Vector3 loc) 
        {
            //Location = loc;
            //objectMesh.Mesh.MoveInstance(loc, objectMesh.GUID);
        }

        public void RotateBy(Vector3 rot)
        {
            Vector3 currentRotation = Rotation;

            currentRotation.X += rot.X;
            currentRotation.Y += rot.Y;
            currentRotation.Z += rot.Z;

            //Rotation = currentRotation;

            //objectMesh.Mesh.RotateInstanceTo(objectRotation, objectMesh.GUID);
        }

        public void RotateTo(Vector3 rot)
        {
            //Rotation = rot;
            //objectMesh.Mesh.RotateInstanceTo(rot, objectMesh.GUID);
        }

        public void AddOrder(Order o)
        {
            //orderList.AddOrder(o);
            if (currentOrder == -1) currentOrder = 0;
        }

        public void AddOrderAt(Order o, int place)
        {
            //orderList.AddOrderAt(o, place);
            if (currentOrder == -1) currentOrder = 0;
        }

        //public new String Name
        //{
            //get { return objectInfo.Name;}
            //set { objectInfo.Name = value; }
        //}

        public bool NeedNewInterimDestination
        {
            get { return needNewInterimDestination; }
        }

        public virtual void DoMove(float fractionElapsed)
        {

        }

        public bool IsStopped
        {
            get { return isStopped; }
            set { isStopped = value; }
        }

        public VehicleInfo VehicleInformation
        {
            get { return vehicleInfo; }
        }

        public List<Order> Orders
        {
            get { return orderList; }
        }

        public string StatusText
        {
            get
            {
                if (IsStopped)
                {
                    return "Stopped.";
                }
                else
                {
                    return "Moving at " + vehicleInfo.MaxSpeed + "mph.";
                }
            }
        }

        public bool IsInService
        {
            get { return isInService; }
        }

    }
}
